﻿using System;
using System.Configuration;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Web.Http;
using System.Web.Http.Controllers;
using Common.Logging;
using In.Api.Dto.HisWs;
using Newtonsoft.Json;
using OutDbContext;
using Rmq.Center;
using Senparc.Weixin.MP.TenPayLib;
using User.Api.BizExtensions;
using User.Api.Dto.Reg;
using User.Api.Helpers;
using User.Api.HttpClients;
using System.Collections.Generic;
using System.Data.Entity.SqlServer;
using System.Data.SqlClient;
using Senparc.Weixin.MP.CommonAPIs;

namespace User.Api.Controllers
{


    public class RegController : ApiController
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(RegController));

        private static readonly object OrderNoLocker = new object();
        private static readonly object PayNotifyLocker = new object();
        private static TenPayInfo _tenPayInfo;

        public static TenPayInfo TenPayInfo
        {
            get
            {
                if (_tenPayInfo == null)
                {
                    _tenPayInfo =
                        TenPayInfoCollection.Data[ConfigurationManager.AppSettings["WeixinPay_PartnerId"]];
                }
                return _tenPayInfo;
            }
        }

        /// <summary>
        /// 生成预约订单，包含预约操作
        /// </summary>
        /// <param name="cardId">就诊卡id</param>
        /// <param name="deptId">科室院内编号</param>
        /// <param name="deptName">科室名称</param>
        /// <param name="doctorId">医生院内编号</param>
        /// <param name="doctorName">医生名称</param>
        /// <param name="regDate">挂号日期</param>
        /// <param name="timeSlice">排班时段</param>
        /// <param name="startTime">分时开始时间</param>
        /// <param name="endTime">分时结束时间</param>
        /// <param name="regType">号源类型</param>
        /// <param name="sqno">分时序号</param>
        /// <param name="fee">费用</param>
        /// <param name="treatFee">治疗费用</param>
        /// <param name="otherFee">其他分i鄂永</param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("CreateApptOrder")]
        public CreateApptOrderResponse CreateApptOrder(int cardId, string deptId, string deptName,
            string doctorId, string doctorName, string regDate, string timeSlice, string startTime,
            string endTime, string regType, string sqno, string fee, string treatFee, string otherFee, string scheduleItemCode)
        {
            var azUser = AzUser.GetInApi(Request);
            Card card;
            string openid;
            ApptOrder order;
            using (var _ctx = new HzfyWeiXinEntities())
            {
                card = _ctx.HospCard.Where(x => x.Id == cardId && x.WxUserId == azUser.UserId)
                    .Select(x => new Card
                    {
                        CardNo = x.CardNo,
                        Birthdate = x.Birthdate,
                        CardType = x.CardType,
                        PatientId = x.PatientId,
                        PatientName = x.PatientName
                    }).FirstOrDefault();
                if (card == null)
                {
                    return new CreateApptOrderResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "找不到就诊卡信息"
                    };
                }

                var sameOrder = _ctx.ApptOrder.IsStatus(ApptOrderExtensions.OrderStatus.取号成功)
                    .FirstOrDefault(x =>
                        x.CardNo == card.CardNo
                        && x.RegDate == regDate
                        );
                if (sameOrder != null)
                {
                    return new CreateApptOrderResponse
                    {
                        ResultCode = "2",
                        ResultMsg = "此卡号当天已有预约信息，不能再预约。一个卡号每天只能预约一个医生，一个预约时段！"
                    };
                }


                var cardSameDayAppointMax = ConfigurationManager.AppSettings["CardSameDayAppointMax"].ToInt32();
                var cardApptCount = _ctx.ApptOrder.IsStatus(ApptOrderExtensions.OrderStatus.取号成功)
                    .Count(x => x.CardNo == card.CardNo && x.RegDate == regDate);
                if (cardApptCount >= cardSameDayAppointMax)
                {
                    return new CreateApptOrderResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "同一天最多可以预约挂号" + cardSameDayAppointMax + "次!"
                    };
                }

                var userobj = _ctx.WxUser.FirstOrDefault(x => x.Id == azUser.UserId);
                openid = userobj == null ? "" : userobj.OpenId;

                var orderNo = GenerateNewOrderNo();
                //新建订单
                order = new ApptOrder
                {
                    WxUserId = azUser.UserId,
                    BranchNo = scheduleItemCode,
                    OrderType = ApptOrderExtensions.OrderType.预约.ToInt32().ToString(), //微信预约订单
                    CardType = card.CardType.ToString(),
                    CardNo = card.PatientId,
                    DeptId = deptId,
                    DeptName = deptName,
                    DoctorId = doctorId,
                    DoctorName = doctorName,
                    OrderNo = orderNo,
                    RegDate = regDate,
                    OrderStatus = ApptOrderExtensions.OrderStatus.未锁号.ToInt32(), //新订单，未锁号（0）
                    TimeSlice = timeSlice,
                    StartTime = startTime,
                    EndTime = endTime,
                    RegType = regType,
                    PayState = ApptOrderExtensions.PayState.未付款.ToInt32().ToString(), //未支付
                    Fee = fee.ToDecimalOrDefault(),
                    TreatFee = treatFee.ToDecimalOrDefault(),
                    OtherFee = otherFee.ToDecimalOrDefault(),
                    SumFee = fee.ToDecimalOrDefault() + treatFee.ToDecimalOrDefault() + otherFee.ToDecimalOrDefault(),
                    CreateTime = DateTime.Now,
                    Sqno = sqno,
                    CardName = card.PatientName
                };

                _ctx.ApptOrder.Add(order);
                _ctx.SaveChanges();

                order.OrderStatus = ApptOrderExtensions.OrderStatus.锁号中.ToInt32();
                _ctx.SaveChanges();
            }

            //执行锁号操作
            var lockRequest = new ExeLockSourceRequest();
            lockRequest.OrderId = order.OrderNo;
            lockRequest.RegDate = order.RegDate;
            lockRequest.RegType = order.BranchNo;
            lockRequest.StartTime = order.StartTime;
            lockRequest.EndTime = order.EndTime;
            lockRequest.CardNo = order.CardNo;
            lockRequest.CardType = order.CardType;

            ExeLockSourceResponse lockResponse;

            try
            {
                var httpClient = InHttpClient.GetClient();
                var responseMsg = httpClient.PostAsJsonAsync("HisWs/ExeLockSource", lockRequest).Result;
                responseMsg.EnsureSuccessStatusCode();
                lockResponse = responseMsg.Content.ReadAsAsync<ExeLockSourceResponse>().Result;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用院内锁号Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

                using (var _ctx = new HzfyWeiXinEntities())
                {
                    SqlParameter[] para =
                        {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.锁号失败.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                     };
                    _ctx.Database.ExecuteSqlCommand(
                        "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
                }

                return new CreateApptOrderResponse
                {
                    ResultCode = "7",
                    ResultMsg = "执行锁号操作超时"
                };
            }

            if (lockResponse.ResultCode != "0")
            {
                using (var _ctx = new HzfyWeiXinEntities())
                {
                    SqlParameter[] para =
                        {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.锁号失败.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                     };
                    _ctx.Database.ExecuteSqlCommand(
                        "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
                }

                return new CreateApptOrderResponse
                {
                    ResultCode = "8",
                    ResultMsg = lockResponse.ResultDesc
                };
            }

            using (var _ctx = new HzfyWeiXinEntities())
            {
                SqlParameter[] para =
                {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.锁号成功.ToInt32()),
                    new SqlParameter("@RegNo", lockResponse.LockQueueNo),
                    new SqlParameter("@LockTime", DateTime.Now),
                    new SqlParameter("@OrderId", order.Id),
                };
                _ctx.Database.ExecuteSqlCommand(
                    "Update ApptOrder set OrderStatus= @OrderStatus, RegNo= @RegNo,LockTime = @LockTime where Id=@OrderId", para);
            }

            // 费用为0的直接设置为支付成功
            if (order.SumFee == 0)
            {
                using (var _ctx = new HzfyWeiXinEntities())
                {
                    SqlParameter[] para = new SqlParameter[]
                    {
                        new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.支付成功.ToInt32()),
                        new SqlParameter("@WxTransactionId", "0"),
                        new SqlParameter("@PayTime", DateTime.Now),
                        new SqlParameter("@PayState", ApptOrderExtensions.PayState.已付款.ToInt32().ToString()),
                        new SqlParameter("@OrderId", order.Id)
                    };
                    _ctx.Database.ExecuteSqlCommand(
                        "Update ApptOrder set OrderStatus= @OrderStatus,PayTime = @PayTime,PayState=@PayState, " +
                        "WxTransactionId=@WxTransactionId where Id=@OrderId", para);
                }

                // RMQ 执行取号
                var pickupingProducer = new OrderPickupingProducer();
                pickupingProducer.Publish(new OrderPickupingMsg
                {
                    OrderType = OrderType.挂号订单,
                    OrderId = order.Id
                });

                return new CreateApptOrderResponse
                {
                    ResultCode = "0",
                    ResultMsg = "",
                    OrderId = order.Id,
                    OrderNo = order.OrderNo,
                    PayString = ""
                };
            }

            //order.OrderStatus = ApptOrderExtensions.OrderStatus.支付中.ToInt32();
            //_ctx.SaveChanges();

            using (var _ctx = new HzfyWeiXinEntities())
            {
                SqlParameter[] para =
                    {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.支付中.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                     };
                _ctx.Database.ExecuteSqlCommand(
                    "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
            }

            // RMQ 16分钟后如果还是支付中则设置支付失败
            var payingTimeoutProducer = new OrderPayingTimeoutProducer();
            payingTimeoutProducer.Publish(new OrderPayingTimeoutMsg
            {
                OrderType = OrderType.挂号订单,
                OrderId = order.Id
            }, 16 * 60 * 1000);

            //组织 微信 js 支付方法 getBrandWCPayRequest 的参数
            var payStartTime = System.DateTime.Now.ToString("yyyyMMddHHmmss");
            var payExpireTime = System.DateTime.Now.AddMinutes(15).ToString("yyyyMMddHHmmss");

            var payFee = (order.SumFee * 100).ToInt32().ToString();
            var superOpenIds = ConfigurationManager.AppSettings["OpenIdsForPayMin"]
                .Split(" , ", StringSplitOptions.RemoveEmptyEntries);
            if (superOpenIds.Contains(order.WxUserId.ToString()))
            {
                payFee = "1";
            }

            var result = WeixinPayV3Helper.ComposeJsApiParameter("JSAPI", "就诊挂号", "AP" + order.OrderNo,
                payFee, GetClientIp(), payStartTime, payExpireTime, "Reg/PaySucceed", openid);

        
            return new CreateApptOrderResponse
            {
                ResultCode = result.ResultCode,
                ResultMsg = result.ResultMsg ?? "",
                PayString = result.Parameter ?? "",
                OrderId = order.Id,
                OrderNo = order.OrderNo,
            };
        }

        /// <summary>
        /// 生成直接挂号订单
        /// </summary>
        /// <returns></returns>
        /// <param name="cardId">就诊卡id</param>
        /// <param name="deptId">科室院内编号</param>
        /// <param name="deptName">科室名称</param>
        /// <param name="doctorId">医生院内编号</param>
        /// <param name="doctorName">医生名称</param>
        /// <param name="regDate">挂号日期</param>
        /// <param name="timeSlice">排班时段</param>
        /// <param name="startTime">分时开始时间</param>
        /// <param name="endTime">分时结束时间</param>
        /// <param name="regType">号源类型</param>
        /// <param name="fee"></param>
        /// <param name="treatFee"></param>
        /// <param name="otherFee"></param>
        /// <param name="sqno"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("CreateDirectOrder")]
        public CreateDirectOrderResponse CreateDirectOrder(int cardId, string deptId, string deptName,
            string doctorId, string doctorName, string regDate, string timeSlice, string startTime,
            string endTime, string regType,string fee, string treatFee, string otherFee,string sqno, string scheduleItemCode)
        {
            var azUser = AzUser.GetInApi(Request);
            Card card;
            ApptOrder order;
            string openid;
            using (var _ctx = new HzfyWeiXinEntities())
            {
                card = _ctx.HospCard.Where(x => x.Id == cardId && x.WxUserId == azUser.UserId)
                    .Select(x => new Card
                    {
                        CardNo = x.CardNo,
                        Birthdate = x.Birthdate,
                        CardType = x.CardType,
                        PatientName = x.PatientName
                    }).FirstOrDefault();
                if (card == null)
                {
                    return new CreateDirectOrderResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "找不到就诊卡信息"
                    };
                }


                //if (System.DateTime.Now.Hour < 8)
                //{
                //    return new CreateDirectOrderResponse
                //    {
                //        ResultCode = "2",
                //        ResultMsg = "很抱歉，现在还不是挂号时间，请您于8点后再挂号！"
                //    };
                //}
                //else if (System.DateTime.Now.Hour >= 12 &&
                //         (String.Compare(DateTime.Now.ToString("HH:mm"), "14:30", StringComparison.Ordinal) < 0))
                //{
                //    return new CreateDirectOrderResponse
                //    {
                //        ResultCode = "2",
                //        ResultMsg = "很抱歉，现在还不是挂号时间，请您于14点30分后再挂号！"
                //    };
                //}

                var sameOrder = _ctx.ApptOrder.IsStatus(ApptOrderExtensions.OrderStatus.取号成功)
                    .FirstOrDefault(x =>
                        x.CardNo == card.CardNo
                        && x.RegDate == regDate
                        && x.DoctorId == doctorId
                        && x.TimeSlice == timeSlice);
                if (sameOrder != null)
                {
                    return new CreateDirectOrderResponse
                    {
                        ResultCode = "2",
                        ResultMsg = "同个医生同个班次，只能挂号一次!"
                    };
                }

                var cardSameDayAppointMax = ConfigurationManager.AppSettings["CardSameDayAppointMax"].ToInt32();
                var cardApptCount = _ctx.ApptOrder.IsStatus(ApptOrderExtensions.OrderStatus.取号成功)
                    .Count(x => x.CardNo == card.CardNo && x.RegDate == regDate);
                if (cardApptCount >= cardSameDayAppointMax)
                {
                    return new CreateDirectOrderResponse
                    {
                        ResultCode = "4",
                        ResultMsg = "同一天最多可以预约挂号" + cardSameDayAppointMax + "次!"
                    };
                }

                var userobj = _ctx.WxUser.FirstOrDefault(x => x.Id == azUser.UserId);
                openid = userobj == null ? "" : userobj.OpenId;

                var orderNo = GenerateNewOrderNo();

                //新建订单
                order = new ApptOrder
                {
                    WxUserId = azUser.UserId,
                    BranchNo= scheduleItemCode,
                    OrderType = ApptOrderExtensions.OrderType.预约.ToInt32().ToString(),
                    // 0-微信平台预约订单  1-其它平台预约订单 2-微信平台挂号订单
                    CardType = "0", //不分卡类型，由HIS识别
                    CardNo = card.CardNo,
                    DeptId = deptId,
                    DeptName = deptName,
                    DoctorId = doctorId,
                    DoctorName = doctorName,
                    OrderNo = orderNo,
                    RegDate = regDate,
                    OrderStatus = ApptOrderExtensions.OrderStatus.未锁号.ToInt32(), //新订单，未锁号（0）
                    TimeSlice = timeSlice,
                    StartTime = startTime,
                    EndTime = endTime,
                    RegType = regType,
                    PayState = ApptOrderExtensions.PayState.未付款.ToInt32().ToString(),
                    Fee = fee.ToDecimalOrDefault(),
                    TreatFee = treatFee.ToDecimalOrDefault(),
                    OtherFee = otherFee.ToDecimalOrDefault(),
                    SumFee = fee.ToDecimalOrDefault() + treatFee.ToDecimalOrDefault() + otherFee.ToDecimalOrDefault(),
                    CreateTime = DateTime.Now,
                    Sqno = sqno,
                    CardName = card.PatientName
                };

                _ctx.ApptOrder.Add(order);
                _ctx.SaveChanges();
            }


            //执行锁号操作
            var lockRequest = new ExeLockSourceRequest();
            lockRequest.OrderId = order.OrderNo;
            lockRequest.RegDate = order.RegDate;
            lockRequest.RegType = order.BranchNo;
            lockRequest.StartTime = order.StartTime;
            lockRequest.EndTime = order.EndTime;
            lockRequest.CardNo = order.CardNo;
            lockRequest.CardType = order.CardType;

            ExeLockSourceResponse lockResponse;

            try
            {
                var httpClient = InHttpClient.GetClient();
                var responseMsg = httpClient.PostAsJsonAsync("HisWs/ExeLockSource", lockRequest).Result;
                responseMsg.EnsureSuccessStatusCode();
                lockResponse = responseMsg.Content.ReadAsAsync<ExeLockSourceResponse>().Result;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用院内锁号Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

                //order.OrderStatus = ApptOrderExtensions.OrderStatus.锁号失败.ToInt32();
                //_ctx.SaveChanges();
                using (var _ctx = new HzfyWeiXinEntities())
                {
                    SqlParameter[] para =
                        {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.锁号失败.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                     };
                    _ctx.Database.ExecuteSqlCommand(
                        "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
                }
                return new CreateDirectOrderResponse
                {
                    ResultCode = "7",
                    ResultMsg = "执行锁号操作超时"
                };
            }

            if (lockResponse.ResultCode != "0")
            {
                //order.OrderStatus = ApptOrderExtensions.OrderStatus.锁号失败.ToInt32();
                //_ctx.SaveChanges();
                using (var _ctx = new HzfyWeiXinEntities())
                {
                    SqlParameter[] para =
                        {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.锁号失败.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                     };
                    _ctx.Database.ExecuteSqlCommand(
                        "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
                }

                return new CreateDirectOrderResponse
                {
                    ResultCode = "8",
                    ResultMsg = lockResponse.ResultDesc
                };
            }

            //order.OrderStatus = ApptOrderExtensions.OrderStatus.锁号成功.ToInt32();
            //order.LockTime = DateTime.Now;
            //_ctx.SaveChanges();
            using (var _ctx = new HzfyWeiXinEntities())
            {
                SqlParameter[] para =
                {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.锁号成功.ToInt32()),
                    new SqlParameter("@RegNo", lockResponse.LockQueueNo),
                    new SqlParameter("@LockTime", DateTime.Now),
                    new SqlParameter("@OrderId", order.Id),
                };
                _ctx.Database.ExecuteSqlCommand(
                    "Update ApptOrder set OrderStatus= @OrderStatus, RegNo= @RegNo,LockTime = @LockTime where Id=@OrderId", para);
            }

            // 费用为0的直接设置为支付成功
            if (order.SumFee == 0)
            {
                using (var _ctx = new HzfyWeiXinEntities())
                {
                    SqlParameter[] para = new SqlParameter[]
                    {
                        new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.支付成功.ToInt32()),
                        new SqlParameter("@WxTransactionId", "0"),
                        new SqlParameter("@PayTime", DateTime.Now),
                        new SqlParameter("@PayState", ApptOrderExtensions.PayState.已付款.ToInt32().ToString()),
                        new SqlParameter("@OrderId", order.Id)
                    };
                    _ctx.Database.ExecuteSqlCommand(
                        "Update ApptOrder set OrderStatus= @OrderStatus,PayTime = @PayTime,PayState=@PayState, " +
                        "WxTransactionId=@WxTransactionId where Id=@OrderId", para);
                }

                // RMQ 执行取号
                var pickupingProducer = new OrderPickupingProducer();
                pickupingProducer.Publish(new OrderPickupingMsg
                {
                    OrderType = OrderType.挂号订单,
                    OrderId = order.Id
                });

                return new CreateDirectOrderResponse
                {
                    ResultCode = "0",
                    ResultMsg = "",
                    OrderId = order.Id,
                    OrderNo = order.OrderNo,
                    PayString = ""
                };
            }

            //order.OrderStatus = ApptOrderExtensions.OrderStatus.支付中.ToInt32();
            //_ctx.SaveChanges();
            using (var _ctx = new HzfyWeiXinEntities())
            {
                SqlParameter[] para =
                    {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.支付中.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                     };
                _ctx.Database.ExecuteSqlCommand(
                    "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
            }

            // RMQ 16分钟后如果还是支付中则设置支付失败
            var payingTimeoutProducer = new OrderPayingTimeoutProducer();
            payingTimeoutProducer.Publish(new OrderPayingTimeoutMsg
            {
                OrderType = OrderType.挂号订单,
                OrderId = order.Id
            }, 16 * 60 * 1000);

            //组织 微信 js 支付方法 getBrandWCPayRequest 的参数
            var payStartTime = System.DateTime.Now.ToString("yyyyMMddHHmmss");
            var payExpireTime = System.DateTime.Now.AddMinutes(15).ToString("yyyyMMddHHmmss");

            var payFee = (order.SumFee * 100).ToInt32().ToString();
            var superOpenIds = ConfigurationManager.AppSettings["OpenIdsForPayMin"]
                .Split(" , ", StringSplitOptions.RemoveEmptyEntries);
            if (superOpenIds.Contains(order.WxUserId.ToString()))
            {
                payFee = "1";
            }


            var result = WeixinPayV3Helper.ComposeJsApiParameter("JSAPI", "就诊挂号", "AP" + order.OrderNo,
              payFee, GetClientIp(), payStartTime, payExpireTime, "Reg/PaySucceed", openid);
         
            return new CreateDirectOrderResponse
            {
                ResultCode = result.ResultCode,
                ResultMsg = result.ResultMsg ?? "",
                PayString = result.Parameter ?? "",
                OrderId = order.Id,
                OrderNo = order.OrderNo,

            };
        }


        /// <summary>
        /// 用户取消支付
        /// </summary>
        /// <param name="orderId">订单id</param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("PayFailed")]
        public PayFailedResponse PayFailed(int orderId)
        {
            Logger.ErrorFormat("Reg orderId Error:{0}", orderId);
            var azUser = AzUser.GetInApi(Request);
            string orderType;
            using (var _ctx = new HzfyWeiXinEntities())
            {
                var order = _ctx.ApptOrder.IsStatus(ApptOrderExtensions.OrderStatus.支付中)
                    .Where(x => x.WxUserId == azUser.UserId && x.Id == orderId).Select(x => new
                    {
                        x.OrderType
                    }).FirstOrDefault();
                if (order == null)
                {
                    return new PayFailedResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "订单不存在"
                    };
                }
                orderType = order.OrderType;

                //order.OrderStatus = ApptOrderExtensions.OrderStatus.支付失败.ToInt32();
                //_ctx.SaveChanges();

                SqlParameter[] para =
                {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.支付失败.ToInt32()),
                    new SqlParameter("@OrderId", orderId),
                };
                _ctx.Database.ExecuteSqlCommand(
                    "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);

            }

            // RMQ 执行取消锁号操作
            var unlockingProducer = new OrderUnlockingProducer();
            unlockingProducer.Publish(new OrderUnlockingMsg
            {
                OrderType = OrderType.挂号订单,
                OrderId = orderId
            });
            //if (orderType == ApptOrderExtensions.OrderType.预约.ToInt32().ToString())
            //{
            //    //// RMQ 执行取消预约操作
            //    //var unapptingProducer = new OrderUnapptingProducer();
            //    //unapptingProducer.Publish(new OrderUnapptingMsg
            //    //{
            //    //    OrderType = Rmq.Center.OrderType.挂号订单,
            //    //    OrderId = orderId
            //    //});

            //    // RMQ 执行取消锁号操作
            //    var unlockingProducer = new OrderUnlockingProducer();
            //    unlockingProducer.Publish(new OrderUnlockingMsg
            //    {
            //        OrderType = OrderType.挂号订单,
            //        OrderId = orderId
            //    });
            //}

            return new PayFailedResponse
            {
                ResultCode = "0",
                ResultMsg = ""
            };
        }


        /// <summary>
        /// 获取挂号状态
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("GetRegStatus")]
        public GetRegStatusResponse GetRegStatus(int orderId)
        {
            var azUser = AzUser.GetInApi(Request);
            using (var _ctx = new HzfyWeiXinEntities())
            {
                var order = _ctx.ApptOrder.Where(x => x.Id == orderId && x.WxUserId == azUser.UserId)
                   .Select(x => new
                    {
                        x.OrderStatus
                    }).FirstOrDefault(); ;
                if (order == null)
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "订单不存在"
                    };
                }

                if (order.OrderStatus == ApptOrderExtensions.OrderStatus.取号中.ToInt32()
                    || order.OrderStatus == ApptOrderExtensions.OrderStatus.支付中.ToInt32()
                    || order.OrderStatus == ApptOrderExtensions.OrderStatus.支付成功.ToInt32())
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "0",
                        ResultMsg = "",
                        RegStatus = "2",
                        FailedMsg = ""
                    };
                }

                if (order.OrderStatus == ApptOrderExtensions.OrderStatus.取号成功.ToInt32())
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "0",
                        ResultMsg = "",
                        RegStatus = "0",
                        FailedMsg = ""
                    };
                }

                return new GetRegStatusResponse
                {
                    ResultCode = "0",
                    ResultMsg = "",
                    RegStatus = "1",
                    FailedMsg = ""
                };
            }
        }

        /// <summary>
        /// 退号操作
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("Unpickup")]
        public UnpickupResponse Unpickup(int orderId)
        {
            var azUser = AzUser.GetInApi(Request);
            using (var _ctx = new HzfyWeiXinEntities())
            {
                var order = _ctx.ApptOrder.IsStatus(ApptOrderExtensions.OrderStatus.取号成功)
                    .Where(x => x.WxUserId == azUser.UserId
                                         && x.Id == orderId).Select(x => new
                                         {
                                             x.RegDate,
                                             x.OrderType
                                         }).FirstOrDefault(); ;
                if (order == null || order.OrderType != ApptOrderExtensions.OrderType.预约.ToInt32().ToString())
                {
                    return new UnpickupResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "找不到订单"
                    };
                }

                if (string.CompareOrdinal(order.RegDate ?? "", DateTime.Today.ToString("yyyy-MM-dd")) <= 0)
                {
                    return new UnpickupResponse
                    {
                        ResultCode = "2",
                        ResultMsg = "退预约号必须在就诊前一天16:00之前"
                    };
                }
            }

            // RMQ 执行退号
            var unpickupProducer = new OrderUnpickupingProducer();
            unpickupProducer.Publish(new OrderUnpickupingMsg
            {
                OrderType = OrderType.挂号订单,
                OrderId = orderId,
                Reason = 1,
            });

            return new UnpickupResponse
            {
                ResultCode = "0",
                ResultMsg = ""
            };
        }

        /// <summary>
        /// 生成挂号订单号
        /// </summary>
        /// <returns></returns>
        public string GenerateNewOrderNo()
        {
            var orderNo = "WX" + DateTime.Now.Date.ToString("yyyyMMdd");
            lock (OrderNoLocker)
            {
                orderNo += (DateTime.Now - DateTime.Now.Date).TotalMilliseconds.ToString("00000000");
                Thread.Sleep(1);
            }

            return orderNo;
        }

        public string GetClientIp()
        {
            if (Request.Properties.ContainsKey("MS_HttpContext"))
            {
                string ip = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                //判断是否有代理服务器
                if (string.IsNullOrEmpty(ip))
                {
                    //没有代理服务器,如果有代理服务器获取的是代理服务器的IP
                    ip = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
                }

                string pattrn = @"(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])";
                if (!string.IsNullOrEmpty(ip) && System.Text.RegularExpressions.Regex.IsMatch(ip, pattrn))
                {
                    return ip;
                }

                return "127.0.0.1";
            }
            else
            {
                return "127.0.0.1";
            }
        }


        /// <summary>
        /// 微信支付通知回调
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost]
        [ActionName("PaySucceed")]
        public HttpResponseMessage PaySucceed()
        {
            
            var result = WeixinPayV3Helper.ParsePayNotify(Request.RequestUri, Request.Content.ReadAsStringAsync().Result.Copy());
            if (result.ResultCode != "0")
            {
                #region 记录验证失败的支付通知

                using (var _ctx = new HzfyWeiXinEntities())
                {
                    var wxPayNotifyLog = new WxPayNotifyLog();
                    wxPayNotifyLog.Uri = Request.RequestUri.AbsoluteUri;
                    wxPayNotifyLog.IsVerified = 2;
                    wxPayNotifyLog.RecCreateDt = DateTime.Now;
                    _ctx.WxPayNotifyLog.Add(wxPayNotifyLog);
                    _ctx.SaveChanges();
                }

                #endregion
                return new HttpResponseMessage
                {
                    StatusCode = HttpStatusCode.OK,
                    Content = new StringContent(result.FailResponse)
                };
            }
            var transactionId = result.PayOrder.TransactionId;
     
            lock (PayNotifyLocker)
            {
                try
                {
                    OrderBase order = null;
                    using (var _ctx = new HzfyWeiXinEntities())
                    {
                        if (
                            _ctx.WxPayNotifyLog.Any(
                                x => x.TransactionId == transactionId && x.TradeState == 0 && x.IsVerified == 1))
                        {
                            return new HttpResponseMessage
                            {
                                StatusCode = HttpStatusCode.OK,
                                Content = new StringContent(result.SuccessResponse)
                            };
                        }
                        if (result.ResultCode == "0") //成功
                        {

                            if (result.PayOrder.TradeState == "0")
                            {
                                //处理订单 并记录日志
                                if (result.PayOrder.OutTradeNo.StartsWith("AP"))
                                {
                                    var orderNo = result.PayOrder.OutTradeNo.Substring(2);
                                    order = _ctx.ApptOrder.Where(x => x.OrderNo == orderNo).Select(x => new OrderBase
                                    {
                                        OrderStatus = x.OrderStatus,
                                        Id = x.Id,
                                        SumFee = x.SumFee
                                    }).FirstOrDefault();
                                    ;
                                }
                            }
                        }
                    }
                    if (order != null)
                    {
                        if (order.OrderStatus == ApptOrderExtensions.OrderStatus.支付中.ToInt32())
                        {
                            using (var _ctx = new HzfyWeiXinEntities())
                            {
                                var para = new SqlParameter[]
                                {
                                    new SqlParameter("@OrderStatus",
                                        ApptOrderExtensions.OrderStatus.支付成功.ToInt32()),
                                    new SqlParameter("@WxTransactionId", transactionId),
                                    new SqlParameter("@PayTime",
                                        DateTime.ParseExact(result.PayOrder.TimeEnd, "yyyyMMddHHmmss",
                                            CultureInfo.CurrentCulture)),
                                    new SqlParameter("@PayState",
                                        ApptOrderExtensions.PayState.已付款.ToInt32().ToString()),
                                    new SqlParameter("@OrderId", order.Id)
                                };
                                _ctx.Database.ExecuteSqlCommand(
                                    "Update ApptOrder set OrderStatus= @OrderStatus,PayTime = @PayTime,PayState=@PayState, " +
                                    "WxTransactionId=@WxTransactionId where Id=@OrderId", para);
                            }

                            // RMQ 执行取号操作
                            var pickupingProducer = new OrderPickupingProducer();
                            pickupingProducer.Publish(new OrderPickupingMsg
                            {
                                OrderType = Rmq.Center.OrderType.挂号订单,
                                OrderId = order.Id
                            });
                        }
                        else if (order.OrderStatus == ApptOrderExtensions.OrderStatus.取消预约成功.ToInt32() ||
                                 order.OrderStatus == ApptOrderExtensions.OrderStatus.支付失败.ToInt32())
                        {
                            //如果订单状态为取消预约成功、支付失败
                            // RMQ 执行退费操作
                            if (order.SumFee > 0)
                            {
                                var refundingProducer = new OrderRefundingPickupFailedProducer();
                                refundingProducer.Publish(new OrderRefundingPickupFailedMsg
                                {
                                    OrderType = OrderType.挂号订单,
                                    OrderId = order.Id
                                });
                            }
                        }

                    }

                    using (var _ctx = new HzfyWeiXinEntities())
                    {
                        //记录通知日志
                        var orderNotifyLog = new WxPayNotifyLog
                        {
                            ServiceVersion = result.PayOrder.ServiceVersion,
                            Attach = result.PayOrder.Attach,
                            BankBillNo = result.PayOrder.BankBillNo,
                            BankType = result.PayOrder.BankType,
                            BuyerAlias = result.PayOrder.BuyerAlias,
                            Discount = result.PayOrder.Discount.ToNullableInt32(),
                            //FeeType = result.PayOrder.FeeType.ToNullableInt32(),
                            InputCharset = result.PayOrder.InputCharset,
                            NotifyId = result.PayOrder.NotifyId,
                            SignType = result.PayOrder.SignType,
                            Sign = result.PayOrder.Sign,
                            SignKeyIndex = result.PayOrder.SignKeyIndex.ToNullableInt32(),
                            //TradeMode = result.PayOrder.TradeMode.ToNullableInt32(),
                            TradeState = result.PayOrder.TradeState.ToNullableInt32(),
                            PayInfo = result.PayOrder.PayInfo,
                            Partner = result.PayOrder.Partner,
                            TotalFee = result.PayOrder.TotalFee.ToNullableInt32(),
                            TransactionId = result.PayOrder.TransactionId,
                            OutTradeNo = result.PayOrder.OutTradeNo,
                            TimerEnd = result.PayOrder.TimeEnd,
                            TransportFee = result.PayOrder.TransportFee.ToNullableInt32(),
                            ProductFee = result.PayOrder.ProductFee.ToNullableInt32(),
                            PostAppId = result.PayUser.AppId,
                            PostTimeStamp = result.PayUser.TimeStamp,
                            PostNonceStr = result.PayUser.NonceStr,
                            PostOpenId = result.PayUser.OpenId,
                            PostAppSignature = result.PayUser.AppSignature,
                            PostIsSubscribe = result.PayUser.IsSubscribe,
                            Uri = Request.RequestUri.AbsoluteUri,
                            IsVerified = 1,
                            RecCreateDt = DateTime.Now
                        };


                        _ctx.WxPayNotifyLog.Add(orderNotifyLog);
                        _ctx.SaveChanges();
                    }

                    return new HttpResponseMessage
                    {
                        StatusCode = HttpStatusCode.OK,
                        Content = new StringContent(result.SuccessResponse)
                    };
                }
                catch (System.Data.SqlClient.SqlException sqlEx)
                {
                    Logger.ErrorFormat("Reg PaySuccessed SqlException Error:{0}", JsonConvert.SerializeObject(sqlEx));
                }
                catch (Exception e)
                {
                    Logger.ErrorFormat("Reg PaySuccessed Error:{0}", JsonConvert.SerializeObject(e));

                }
            }

            #region 记录验证失败的支付通知

            using (var _ctx = new HzfyWeiXinEntities())
            {
                var unverifiedNotifyLog = new WxPayNotifyLog();
                unverifiedNotifyLog.Uri = Request.RequestUri.AbsoluteUri;
                unverifiedNotifyLog.IsVerified = 0;
                unverifiedNotifyLog.RecCreateDt = DateTime.Now;
                _ctx.WxPayNotifyLog.Add(unverifiedNotifyLog);
                _ctx.SaveChanges();
            }

            #endregion

            return new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.OK,
                Content = new StringContent(result.FailResponse)
            };


        }


        /// <summary>
        /// 获取取消挂号状态
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("GetCancellRegStatus")]
        public GetRegStatusResponse GetCancellRegStatus(int orderId)
        {
            var azUser = AzUser.GetInApi(Request);
            using (var _ctx = new HzfyWeiXinEntities())
            {
                var order = _ctx.ApptOrder.FirstOrDefault(x => x.Id == orderId && x.WxUserId == azUser.UserId);
                if (order == null)
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "订单不存在"
                    };
                }

                //对于订单金额为0的挂号单，微信退号中就算成功,不做微信退款操作
                if (order.SumFee == 0 && order.OrderStatus == ApptOrderExtensions.OrderStatus.微信退号中.ToInt32())
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "0",
                        ResultMsg = "",
                        RegStatus = "0",
                        FailedMsg = ""
                    };
                }

                if (order.OrderStatus == ApptOrderExtensions.OrderStatus.微信退号中.ToInt32()
                    || order.OrderStatus == ApptOrderExtensions.OrderStatus.微信退号成功.ToInt32()
                    || order.OrderStatus == ApptOrderExtensions.OrderStatus.微信退号退款中.ToInt32())
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "0",
                        ResultMsg = "",
                        RegStatus = "2",
                        FailedMsg = ""
                    };
                }

                if (order.OrderStatus == ApptOrderExtensions.OrderStatus.微信退号退款成功.ToInt32())
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "0",
                        ResultMsg = "",
                        RegStatus = "0",
                        FailedMsg = ""
                    };
                }

                return new GetRegStatusResponse
                {
                    ResultCode = "0",
                    ResultMsg = "",
                    RegStatus = "1",
                    FailedMsg = ""
                };
            }
        }

        /// <summary>
        /// 手工退费
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [ActionName("test")]
        [AllowAnonymous]
        public GetRegFeeResponse test()
        {
            var appId = AccessTokenContainer.GetFirstOrDefaultAppId();
            Senparc.Weixin.MP.CommonAPIs.AccessTokenContainer.GetAccessTokenResult(appId, true);

            var openId = "o8qol1PXSib9BiFHy9wLibGlCiKQ";
            var message = "cs";
            //var url = GetH5Url("/index/reg-order-detail/" + order.Id);
            Senparc.Weixin.MP.AdvancedAPIs.CustomApi.SendText(null, openId, message);
            //var a = WeixinPayV3Helper.DoRefund("SCWX2017110359181765", "4200000005201711032187885714", "SCWX2017110359181765", 10, 10);
            return new GetRegFeeResponse
            {
                ResultCode = "0",
                ResultMsg = appId,

            };
        }

        //[AllowAnonymous]
        //[HttpGet]
        //[ActionName("TestDoRefund")]
        //public CreateDirectOrderResponse TestDoRefund()
        //{
        //    string outno = "APWX2016061420513411";
        //    int fee = 700;
        //    var result = WeixinPayV3Helper.DoRefund(outno, "4009282001201606147229458705", outno, fee, fee);
        //    return new CreateDirectOrderResponse
        //    {
        //        ResultCode = "1",
        //        ResultMsg = ""
        //    };
        //}


        //[AllowAnonymous]
        //[HttpGet]
        //[ActionName("Pay")]
        //public CreateDirectOrderResponse Pay()
        //{

        //    //组织 微信 js 支付方法 getBrandWCPayRequest 的参数
        //    var payStartTime = System.DateTime.Now.ToString("yyyyMMddHHmmss");
        //    var payExpireTime = System.DateTime.Now.AddMinutes(15).ToString("yyyyMMddHHmmss");

        //    var payFee = (1 * 100).ToInt32().ToString();



        //    var result = WeixinPayV3Helper.ComposeJsApiParameter("就诊挂号", "AP3" ,
        //      payFee, GetClientIp(), payStartTime, payExpireTime, "Reg/PaySucceed", "");

        //    return new CreateDirectOrderResponse
        //    {
        //        ResultCode = "6",
        //        ResultMsg = ""
        //    };
        //}

    }

}

 
